#pragma once
#include <functional>
#include <signal.h>
#include "tcp_socket.hpp"
typedef std::function<void(const std::string& req, std::string* resp)> Handler;
// 多进程版本的 Tcp 服务器
class TcpProcessServer {
public:
	TcpProcessServer(const std::string& ip, uint16_t port) : ip_(ip), port_(port) {
		// 需要处理子进程
		signal(SIGCHLD, SIG_IGN);
	}
	void ProcessConnect(const TcpSocket& new_sock, const std::string& ip, uint16_t port,
		Handler handler) {
		int ret = fork();
		if (ret > 0) {
			// father
			// 父进程不需要做额外的操作, 直接返回即可. 
			// 思考, 这里能否使用 wait 进行进程等待?
			// 如果使用 wait , 会导致父进程不能快速再次调用到 accept, 仍然没法处理多个请求
			// [注意!!] 父进程需要关闭 new_sock
			new_sock.Close();
			return;
		}
		else if (ret == 0) {
			// child
			 // 处理具体的连接过程. 每个连接一个子进程
			for (;;) {
				std::string req;
				bool ret = new_sock.Recv(&req);
				if (!ret) {
					// 当前的请求处理完了, 可以退出子进程了. 注意, socket 的关闭在析构函数中就完成了
					printf("[client %s:%d] disconnected!\n", ip.c_str(), port);
					exit(0);
				}
				std::string resp;
				handler(req, &resp);
				new_sock.Send(resp);
				printf("[client %s:%d] req: %s, resp: %s\n", ip.c_str(), port,
					req.c_str(), resp.c_str());
			}
		}
		else {
			perror("fork");
		}
	}
	bool Start(Handler handler) {
		// 1. 创建 socket;
		CHECK_RET(listen_sock_.Socket());
		// 2. 绑定端口号
		CHECK_RET(listen_sock_.Bind(ip_, port_));
		// 3. 进行监听
		CHECK_RET(listen_sock_.Listen(5));
		// 4. 进入事件循环
		for (;;) {
			// 5. 进行 accept
			TcpSocket new_sock;
			std::string ip;
			uint16_t port = 0;
			if (!listen_sock_.Accept(&new_sock, &ip, &port)) {
				continue;
			}
			printf("[client %s:%d] connect!\n", ip.c_str(), port);
			ProcessConnect(new_sock, ip, port, handler);
		}
		return true;
	}
private:
	TcpSocket listen_sock_;
	std::string ip_;
	uint64_t port_;
};